home *** CD-ROM | disk | FTP | other *** search
- ;-----------------------------------------------------------------
- ; anima.asm
- ; ---------
- ; Assembly Anim stuff.
- ;-----------------------------------------------------------------
-
- include asm.inc
- include anim.inc
-
- HEADER anima
-
- extrn _printf:far
- ;-----------------------------------------------------------------
-
- DSEG
- IF 0
- extrn _doDump:byte
- public _TotBytes
- runMsg db 'run %x',13,0
- dumpMsg db 'dump %x',13,0
- skipMsg db 'skip %x',13,0
- clipMsg db '---dest:%x ',0
- finalMsg db '---dest:%x last-row-bytes:%x--- ',0
- _TotBytes dw 0
- ENDIF
- ENDDS
-
- PSEG anima
-
- ;-----------------------------------------------------------------
- ; void ShortDelay(UWORD delay);
- ; Does a high-speed delay loop.
- ;-----------------------------------------------------------------
-
- public _ShortDelay
- STARTPROC _ShortDelay
-
- SD_DELAY = ARGB
-
- push bp
- mov bp,sp
-
- mov cx,SD_DELAY[bp]
- sd_loop:
- loop sd_loop
-
- pop bp
- ret
-
- ENDPROC _ShortDelay
-
-
- IF 1 ; RunSkipDump format.
- ;-----------------------------------------------------------------
- ; UWORD PlayRunSkipDump(UWORD nBytes, srcSeg, srcAddr, dstSeg, dstAddr);
- ; Finishes playing the Bitmap body with type==RunSkipDump.
- ; RETURN final dstAddr (one byte past last pixel written).
- ; NOTE: since a final skip is omitted, this could be anywhere on the screen.
- ; If there is no final skip, it will be one past the last pixel on the screen.
- ; For a screen starting at address (offset) 0, its greatest value is
- ; the # pixels on the screen.
- ; NOTE: we're ignoring nBytes. Bad data could cause this to write past
- ; end of dst buffer, or even to loop forever.
- ;-----------------------------------------------------------------
-
- public _PlayRunSkipDump
- STARTPROC _PlayRunSkipDump
-
- PR_N_BYTES = ARGB
- PR_SRC_SEG = ARGB+2
- PR_SRC_ADDR = ARGB+4
- PR_DST_SEG = ARGB+6
- PR_DST_ADDR = ARGB+8
-
- push bp
- mov bp,sp
- push si
- push di
- push es
-
- mov si,PR_SRC_ADDR[bp]
- mov di,PR_DST_ADDR[bp]
- mov es,PR_DST_SEG[bp]
-
- push ds ; Save DS:DGROUP.
- mov ds,PR_SRC_SEG[bp] ; SET DS:dstSeg. NOT DGROUP.
-
- sub ch,ch ; SET CH = 0.
- jmp short nextOp
-
- skip:
- sub cl,80h ; Strip off sign bit, leaving skip cnt.
- jz longOp ; cnt==0 indicates a long op.
- ; --- shortSkip ---
- add di,cx ; skip # pixels. (CH=0)
- ; --- variation on NEXTOP inline to minimize jmp's ---
- nextOp: ; Get and decode next op.
- mov cl,[si]
- inc si
- jcxz run
- or cl,cl ; Test CL's sign bit.
- jl skip
- dump:
- rep movsb ; copy # pixels. (CH=0)
- ; --- variation on NEXTOP inline to minimize jmp's ---
- mov cl,[si]
- inc si
- or cl,cl ; Test CL's sign bit.
- jl skip
- jg dump
- run:
- mov cl,[si] ; 8-bit unsigned count.
- inc si
- lodsb ; pixel value.
- rep stosb ; set # pixels to value. (CH=0)
- ; --- variation on NEXTOP inline to minimize jmp's ---
- mov cl,[si]
- inc si
- jcxz run
- or cl,cl ; Test CL's sign bit.
- jl skip
- jmp short dump
-
- longOp: ; NOTE: if load into CX, must clear CH afterwards.
- lodsw ; 16-bit unsigned count.
- or ax,ax ; set flags.
- jle notLongSkip
- ;longSkip:
- add di,ax ; skip # pixels.
- jmp short nextOp
- ; longSkip only used for > 2*127, so can't be very many,
- ; so don't bother saving one jmp with inline NEXTOP.
-
- notLongSkip:
- jz stop ; long count of zero means "stop code".
- mov cx,ax ; may SET CH non-zero.
- sub ch,80h ; Clear sign bit.
- cmp ch,40h
- jge longRun
- ; --- For maximum speed on longDump, caller should insure src & dst are
- ; aligned. To do so, caller must calculate whether
- ; src DATA will begin on same (odd or even) alignment as dst data.
- ; If not, first put a 1-byte Dump, which occupies 2 src bytes, thereby
- ; shifting relative alignment (src moves 2, dst moves 1).
- ;longDump
- test si,1 ; Insure src word-aligned.
- ; In case caller didn't sync src & dst, we chose
- ; to align src because we know it is of benefit --
- ; aligning dst on 8-bit video cards might not be of
- ; any benefit.
- jz dumpWordAligned
- movsb ; get to word boundary.
- dec cx
- dumpWordAligned:
- shr cx,1 ; Convert byte count to word count.
- jc dumpOddByte
- rep movsw ; Word-aligned.
- longOpDone:
- sub ch,ch ; SET CH = 0.
- jmp short nextOp
-
- dumpOddByte:
- rep movsw ; Word-aligned.
- movsb
- jmp short longOpDone
-
- longRun:
- sub ch,40h ; Clear "longRun" bit.
- lodsb
- mov ah,al ; Replicate byte to word value.
- test di,1 ; Insure dst word-aligned.
- jz runWordAligned
- stosb
- dec cx
- runWordAligned:
- shr cx,1 ; Convert byte count to word count.
- jc runOddByte
- rep stosw ; Word-aligned.
- jmp short longOpDone
-
- runOddByte:
- rep stosw ; Word-aligned.
- stosb
- jmp short longOpDone
-
- stop:
- pop ds ; Restore DS:DGROUP.
-
- mov ax,di ; RETURN final dstAddr.
- pop es
- pop di
- pop si
- pop bp
- ret
-
- ENDPROC _PlayRunSkipDump
-
-
- ;-----------------------------------------------------------------
- ; UWORD MakeRunSkipDump(UWORD src1Seg, src2Seg, finalPixelAddr,
- ; UWORD dstSeg, dstAddr, dstLimit, UWORD *nBytesP,
- ; UWORD srcWidth, finalRowAddr, finalRowWidth,
- ; BOOL inFinalRow, skipPermitted);
- ; Finishes making the Bitmap body with type==RunSkipDump.
- ; RETURN TRUE if fit in deltaX.
- ; SIDE_EFFECT: set deltaX.nBytes, store that many bytes at deltaX.(seg:addr).
- ; ASSUMES srcs start at Addr=0.
- ;-----------------------------------------------------------------
-
- ADDR = 0 ; Field-offsets within a far ptr. 16-bit-offset.
- SEGM = 2 ; Segment.
-
- ; --- registers ---
- ; AL: pixel. Value of current src2 pixel.
- ; AH: runPix. Value of pixels in current Run.
- ; BL: skipInDump. # skippable bytes in Dump or Run.
- ; BH: runInDump. # runnable bytes in Dump.
- ; CX: wordCnt. # pixels processed for current op.
- ; DX: -- temporary.
- ; DS:SI: src2.
- ; ES:DI: src1 or dst. -- careful, ES:DI used for two purposes.
-
- public _MakeRunSkipDump
- STARTPROC _MakeRunSkipDump
-
- MR_SRC1_SEG = ARGB
- MR_SRC2_SEG = ARGB+2
- MR_FINAL_PIXEL_ADDR = ARGB+4
- MR_DST_SEG = ARGB+6
- MR_DST_ADDR = ARGB+8 ; dst0 -- save so can calculate size.
- MR_DST_LIMIT = ARGB+10 ; dstLimit => dstAddr musn't pass this.
- MR_N_BYTES_PTR = ARGB+12
- MR_SRC_WIDTH = ARGB+14
- MR_FINAL_ROW_ADDR = ARGB+16
- MR_FINAL_ROW_WIDTH = ARGB+18
- MR_IN_FINAL_ROW = ARGB+20
- MR_SKIP_PERMITTED = ARGB+22
- ; --- locals
- MR_SRC1_FAR = -4 ; ES:DI when addressing src1.
- MR_DST_FAR = -8 ; ES:DI when addressing dst.
- MR_MUST_STOP = -9 ; BOOL mustStop. Have reached end of src data.
- ;unused byte... MR_??? = -10 ; BOOL ???
- MR_X = -12 ; current x-coordinate.
- MR_LARGE_SKIP_LIMIT = -14 ; At or beyond here, don't try to do large skip.
- MR_WAS_X = -16 ; x-coordinate where op's data started.
- mLOCALS = 16 ; Total local space to save.
-
- push bp
- mov bp,sp
- sub sp,mLOCALS
- push si
- push di
- push es
-
- IF 0 ; debugging
- mov _TotBytes,0
- ENDIF
- ; --- Simplify "incompressible" checking. We don't care if we are
- ; slightly over-conservative. 7 allows 3B for long skip, 4B for any
- ; other op. This allows us to not check at all on a short skip
- ; (a >4B series of short skips would never be done -- long skip done instead),
- ; and to check run or dump overhead without subtracting the size of the
- ; overhead.
- sub word ptr MR_DST_LIMIT[bp],7
-
-
- ; --- Simplify check of limit for "large skip" code. The limit is determined
- ; by the need to have CLIP_X see the transition to the final scan row.
- mov dx,MR_FINAL_ROW_ADDR[bp]
- sub dx,MR_SRC_WIDTH[bp] ; Paranoia -- a whole row before final.
- sub dx,4 ; Make sure CLIP_X gets a chance.
- mov MR_LARGE_SKIP_LIMIT[bp],dx
-
-
- ; --- Prepare far ptrs for "les di,...".
- sub di,di ; SET src1.
- mov ax,MR_SRC1_SEG[bp]
- mov MR_SRC1_FAR+ADDR[bp],di
- mov MR_SRC1_FAR+SEGM[bp],ax
- mov di,MR_DST_ADDR[bp] ; SET dst. SET DI:dstAddr.
- mov ax,MR_DST_SEG[bp]
- mov MR_DST_FAR+ADDR[bp],di
- mov MR_DST_FAR+SEGM[bp],ax
-
- ; --- ASSUME srcs start at Addr=0.
- sub si,si ; SET (DS:SI):src2.
- push ds ; Save DS:DGROUP.
- mov ds,MR_SRC2_SEG[bp] ; SET DS:dstSeg. NOT DGROUP.
- ; --- DGROUP NOT ACCESSIBLE VIA DS BELOW. USE SS IF NEED DGROUP. ---
-
- les di,MR_DST_FAR[bp] ; SET ES:DI:dst.
- mov ax,BMBODY_RUNSKIPDUMP
- stosw ; *(UWORD far *)dst++ =
- ; 2-byte header containing type.
- mov MR_DST_FAR+ADDR[bp],di ; Save dstAddr, so DI can be re-used.
-
- les di,MR_SRC1_FAR[bp] ; *** SET ES:DI:src1 for loops ***
-
- sub dx,dx ; 0.
- mov MR_X[bp],dx ; "x=0;"
- mov MR_MUST_STOP[bp],dl ; "mustStop = FALSE;"
-
- notInASequence:
- sub cx,cx ; CX:wordCnt=0.
-
- ; ----------------------- Dump -------------------------------------------
- ; ASSUME ES:DI: src1.
- ; "pixel" must be set when jump to beDump with "wordCnt != 0".
- beDump:
- mov dx,MR_X[bp] ;
- sub dx,cx ; CX:wordCnt.
- jge Dxw
- add dx,MR_SRC_WIDTH[bp] ; started on previous line
- Dxw: mov MR_WAS_X[bp],dx
-
- sub bx,bx ; SET BL:skipInDump=0, BH:runInDump=0.
- or cx,cx ; test CX:wordCnt.
- jz DnoCnt
- inc bh ; BH:runInDump. Any pixel is run==1.
- DnoCnt:
- inDump:
- mov dx,MR_X[bp]
- cmp dx,MR_SRC_WIDTH[bp]
- jne DnoClip
- call ClipX ; "CLIP_X(stopDump);"
- jnz stopDump
- DnoClip:
-
- mov ah,al ; AH,AL: "runPix = pixel;"
- lodsb ; "pixel = *src2++;" Get&count byte
- inc word ptr MR_X[bp] ; "x++;"
- inc cx ; CX: "wordCnt++;"
-
- cmp al,es:[di] ; AL:pixel. ES:DI:src1.
- je DSkip ; "if (pixel != *src1)"
- mov bl,0ffh ; "-1" & inc below => "skipInDump=0"
- DSkip:
- inc bl ; BL: "skipInDump++;"
- inc di ; DI: "src1++;"
-
- cmp al,ah ; "if (pixel != runPix)"
- je DRun
- sub bh,bh ; "0" & inc below => "runInDump=1"
- ; Any pixel is a run of 1.
- DRun:
- inc bh ; BH: "runInDump++;"
-
- cmp bl,MIN_SKIP ; "if (skipInDump == MIN_SKIP"
- jne DnoSkip
- test byte ptr MR_SKIP_PERMITTED[bp],1 ; " && skipPermitted)"
- jz DnoSkip
- ; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_SKIP);"
- push bx
- push cx
- mov bx,si ; SET BX:param1. SI:src2Addr.
- sub bx,cx ; CX:wordCnt.
- sub cx,MIN_SKIP ; SET CX:param2 = CX:wordCnt-MIN_SKIP.
- call PutDump
- pop cx
- pop bx
-
- mov cx,MIN_SKIP ; CX:wordCnt.
- jmp beSkip
- DnoSkip:
-
- cmp bh,MIN_RUN ; "if (runInDump == MIN_RUN)"
- jne noRID
- ; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_RUN);"
- push bx
- push cx
- mov bx,si ; SET BX:param1. SI:src2Addr.
- sub bx,cx ; CX:wordCnt.
- sub cx,MIN_RUN ; SET CX:param2 = CX:wordCnt-MIN_RUN.
- call PutDump
- pop cx
- pop bx
-
- mov cx,MIN_RUN ; CX:wordCnt.
- jmp short beRun
- noRID:
-
- ; --- Byte still in Dump.
- cmp cx,MAX_LONG_DUMP ; "if (wordCnt == MAX_LONG_DUMP)"
- jne inDump
- stopDump:
- ; --- "PUT_DUMP(src2-wordCnt, wordCnt);"
- push bx
- push cx
- mov bx,si ; SET BX:param1. SI:src2Addr.
- sub bx,cx ; CX:wordCnt.
- ; ; SET CX:param2 = CX:wordCnt.
- call PutDump
- pop cx
- pop bx
-
- test byte ptr MR_MUST_STOP[bp],1
- jnz Dstop
- jmp notInASequence
- Dstop: jmp beStop
-
-
- ; ----------------------- Run -------------------------------------------
- ; ASSUME ES:DI: src1.
- beRun:
- mov dx,MR_X[bp] ;
- sub dx,cx ; CX:wordCnt.
- jge Rxw
- add dx,MR_SRC_WIDTH[bp] ; started on previous line
- Rxw: mov MR_WAS_X[bp],dx
-
- sub bx,bx ; SET BL:skipInDump=0.
- mov ah,al ; "runPix = pixel;"
- inRun:
- mov dx,MR_X[bp]
- cmp dx,MR_SRC_WIDTH[bp]
- jne RnoClip
- call ClipX ; "CLIP_X(stopRun);"
- jnz stopRun
- RnoClip:
-
- lodsb ; "pixel = *src2++;" Get&count byte
- inc word ptr MR_X[bp] ; "x++;"
- inc cx ; CX: "wordCnt++;"
-
- cmp al,es:[di] ; AL:pixel. ES:DI:src1.
- je RSkip ; "if (pixel != *src1)"
- mov bl,0ffh ; "-1" & inc below => "skipInDump=0"
- RSkip:
- inc bl ; BL: "skipInDump++;"
- inc di ; DI: "src1++;"
-
- ; Note: check for byte runnable comes later.
-
- cmp bl,MIN_RUN_SKIP ; "if (skipInDump == MIN_RUN_SKIP"
- jne RnoSkip
- test byte ptr MR_SKIP_PERMITTED[bp],1 ; " && skipPermitted)"
- jz RnoSkip
- sub cx,MIN_RUN_SKIP ; retract skip bytes from wordCnt.
- ; --- "PUT_RUN(wordCnt, runPix);"
- call PutRun ; CX:wordCnt, AH:runPix. Must Preserve.
-
- mov cx,MIN_RUN_SKIP ; CX:wordCnt.
- jmp short beSkip
- RnoSkip:
-
- cmp al,ah ; "if (pixel != runPix)"
- je Rrun
- dec cx ; Retract pixel from Run.
- ; --- "PUT_RUN(wordCnt, runPix);"
- call PutRun ; CX:wordCnt, AH:runPix. Must Preserve.
-
- mov cx,1 ; CX:wordCnt.
- jmp beDump
-
- ; --- Byte runnable.
- Rrun:
- cmp cx,MAX_LONG_RUN ; "if (wordCnt == MAX_LONG_RUN)"
- jne inRun
- stopRun:
- ; --- "PUT_RUN(wordCnt, runPix);"
- call PutRun ; CX:wordCnt, AH:runPix. Must Preserve.
-
- test byte ptr MR_MUST_STOP[bp],1
- jnz Dstop ; ("jmp beStop" was out of range.)
- jmp notInASequence
-
-
- ; ----------------------- Skip -------------------------------------------
- beSkip:
-
- ; ---------------- Attempt to quickly skip a long ways forward.
- mov dx,MR_LARGE_SKIP_LIMIT[bp]
- sub dx,si
- jb inSkip0 ; Too close to end.
-
- push cx ; Hold CX:wordCnt.
- mov cx,dx ; Permit skip up to skipLimit.
- shr cx,1 ; As # words.
- mov dx,cx ; SET DX: # words to cnt down.
- jcxz skippedAll
- repe cmpsw
-
- je skippedAll ; last words eql; cnt stopped us.
- sub si,2 ; Retract the non-matching word.
- sub di,2
- inc cx
- skippedAll:
- sub dx,cx ; # skip words found.
- shl dx,1 ; # skip bytes found.
-
- pop cx ; Restore CX:wordCnt.
- add cx,dx ; wordCnt now reflects new skip bytes.
- add dx,MR_X[bp] ; x += bytes found, mod width.
- SmodX: sub dx,MR_SRC_WIDTH[bp] ; force it to underflow.
- jnb SmodX
- add dx,MR_SRC_WIDTH[bp] ; compensate for underflow.
- SxOk: mov MR_X[bp],dx
- ; ----------------
- jmp short inSkip
-
-
- ; --- Byte skippable. Final Skip is NOT output prior to Stop.
- skippable:
- inc di ; DI: "src1++;"
-
- inSkip0:
- mov dx,MR_X[bp]
- cmp dx,MR_SRC_WIDTH[bp]
- je Sclip
- ; --- fall through to "inSkip".
-
- inSkip:
- lodsb ; "pixel = *src2++;" Get&count byte
- inc word ptr MR_X[bp] ; "x++;"
- inc cx ; CX: "wordCnt++;"
-
- cmp al,es:[di] ; AL:pixel. ES:DI:src1.
- je skippable ; "if (pixel != *src1)"
- ; --- Byte not skippable. Put the Skip. *** AX:temporary.***
- ; NOTE: Subtracted enough from dstLimit, that we're not bothering to
- ; check for incompressible (destination buffer overflow) on short skips.
- inc di ; DI: "src1++;"
- push ax ; Hold AX. "jmp SOutDone" for POP.***
- ; IF CHANGE # regs pushed, must change SOutDone & Sincompressible.
-
- mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI.
- les di,MR_DST_FAR[bp] ; SET ES:DI:dst.
-
- dec cx ; "wordCnt--;" Retract pixel.
- IF 0
- call DumpPutSkip
- ENDIF
- cmp cx,MAX_SHORT_SKIP
- ja SnotShort
- ; --- One Short Skip.
- mov al,OP_SKIP ; "*dst++ = OP_SKIP | wordCnt;"
- or al,cl
- stosb
- jmp short SOutDone
-
- SnotShort:
- cmp cx,2*MAX_SHORT_SKIP
- ja Slong
- ; --- Two Short Skips.
- mov al,OP_SKIP ; "*dst++ = OP_SKIP | MAX_SHORT_SKIP;"
- or al,MAX_SHORT_SKIP
- stosb
- sub cx,MAX_SHORT_SKIP ; "wordCnt-= MAX_SHORT_SKIP;"
- mov al,OP_SKIP ; "*dst++ = OP_SKIP | wordCnt;"
- or al,cl
- stosb
- jmp short SOutDone
- Slong:
- mov dx,cx ; SET DX:wordCnt0 = wordCnt.
- Slong0: mov cx,dx ; "while (wordCnt0) {..."
- jcxz SOutDone
- cmp di,MR_DST_LIMIT[bp] ; Check for incompressible.
- ja Sincompressible
- cmp cx,MAX_LONG_SKIP ; "wordCnt = MIN(wordCnt0,MAX_LONG_SKIP);"
- jbe Sfits
- mov cx,MAX_LONG_SKIP
- Sfits: sub dx,cx ; "wordCnt0 -= wordCnt;"
- mov al,LONG_OP ; "*dst++ = LONG_OP;"
- stosb
- mov ax,cx ; "*((UWORD far *)dst++ = wordCnt;"
- stosw
- jmp short Slong0
-
- SOutDone:
- mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr.
- les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1.
- pop ax ; Restore AX. ***
- mov cx,1 ; CX:wordCnt.
- jmp beDump
-
- Sclip: call ClipX ; "CLIP_X(beStop);"
- jnz beStop
- jmp short inSkip ; Skip may be any length up to 64KB-1.
-
- Sincompressible:
- pop ax ; Match "push ax".
- jmp incompressible
-
- ; ----------------------- Stop -------------------------------------------
- beStop:
- mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI.
- les di,MR_DST_FAR[bp] ; SET ES:DI:dst.
- cmp di,MR_DST_LIMIT[bp] ; Check for incompressible.
- ja incompressible
- mov al,LONG_OP ; "*dst++ = LONG_OP;"
- stosb ; Stop is "LongOp #0".
- sub ax,ax ; 0.
- stosw ; "*(UWORD far *)dst++ = 0;"
-
- mov ax,di ; "*nBytesP = dst - dst0;"
- sub ax,MR_DST_ADDR[bp]
- mov bx,MR_N_BYTES_PTR[bp]
- mov ss:[bx],ax ; ASSUME SS=DGROUP.
-
- mov ax,1 ; RETURN TRUE.
- jmp short done
-
- ; --- Body could not be compressed into given buffer size.
- ; Consider it incompressible. (Actually, client may have given a small
- ; buffer, and may wish to re-try with a larger buffer.)
- incompressible:
- sub ax,ax ; RETURN FALSE.
- done:
- pop ds ; Restore DS: DGROUP.
-
- pop es
- pop di
- pop si
- mov sp,bp
- pop bp
- ret ; FAR back to client.
-
-
- ; ------ CLIP_X() -----------------------------------------------------------
- ; No parameters, returns flags according to "test inFinalRow".
- ; DX: -- temporary. ASSUME caller allows destruction.
- ; NOTE: moved per-pixel test into each caller, to save time per pixel.
- ; Therefore, must already know at line end when call ClipX.
- ClipX: mov word ptr MR_X[bp],0
- test byte ptr MR_IN_FINAL_ROW[bp],1
- jz notDone
- mov byte ptr MR_MUST_STOP[bp],1
- IF 0
- call DumpFinal
- ENDIF
- mov dx,1
- or dx,dx ; clear zero flag.
- retn ; NEAR.
- notDone: cmp si,MR_FINAL_ROW_ADDR[bp] ; "if (src2Addr == finalRowAddr)"
- jne notStartingLastLine
- mov dx,MR_FINAL_ROW_WIDTH[bp] ; "w = finalRowWidth;"
- mov MR_SRC_WIDTH[bp],dx
- mov byte ptr MR_IN_FINAL_ROW[bp],1 ; "inFinalRow = TRUE;"
- notStartingLastLine:
- IF 0
- call DumpClipX
- ENDIF
- sub dx,dx ; set zero flag.
- retn ; NEAR.
-
-
- ; ------ Assembly level routines, with same registers & BP as above, except:
- ; AX: -- temporary. Each routine must SAVE/RESTORE.
- ; DX: -- temporary. ASSUME caller allows destruction.
- ; REMEMBER, DS:src2Seg, NOT DGROUP.
- ; REMEMBER, ES:DI: src1. DI must be updated to MR_SRC1_FAR+ADDR[bp], if
- ; need to use it for dst.
-
-
- ; ------ PutRun(CX:wordCnt, AH:runPix) --------------------------------------
- ; Must Preserve all registers, including parameters.
- PutRun:
- jcxz noRun
- IF 0
- call DumpPutRun
- ENDIF
- push ax ; Hold AX. Last, so can access runPix.
- ; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible.
-
- mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI.
- les di,MR_DST_FAR[bp] ; SET ES:DI:dst.
- cmp di,MR_DST_LIMIT[bp] ; Check for incompressible.
- ja Rincompressible
- cmp cx,MAX_SHORT_RUN ;
- ja lRun ; "wordCnt > MAX_SHORT_RUN"
- mov ax,MR_WAS_X[bp]
- add ax,cx
- cmp ax,MR_SRC_WIDTH[bp]
- ja lRun ; "CROSSED_W(wordCnt)"
- mov al,OP_RUN ; "*dst++ = OP_RUN;"
- stosb
- mov al,cl ; "*dst++ = wordCnt;"
- stosb
- jmp short rBody
- lRun: ; longRun op.
- mov al,LONG_OP ; "*dst++ = LONG_OP;"
- stosb
- mov ax,cx ; "*((UWORD far *)dst++ = "
- or ah,LONG_RUN ; " (LONG_RUN<<8) | wordCnt);"
- stosw
- rBody:
- pop ax ; ACCESS AH:runPix.
- push ax
- mov al,ah
- stosb ; "*dst++ = runPix;"
-
- mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr.
- les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1.
-
- pop ax ; Restore AX.
- noRun: retn ; NEAR.
-
- Dincompressible:
- ; NOTE: since we're throwing everything away, doesn't matter that
- ; bx & cx aren't the top two items at this point.
- pop ax ; Balance CALLER'S PUSH BX & CX.
- pop ax
- Rincompressible:
- pop ax ; Balances "push ax".
- pop ax ; Remove (near) return address.
- jmp short incompressible
-
- ; --- PutDump(DS:BX:body, CX:cnt).
- ; BX: param1. ASSUME caller allows destruction.
- ; CX: param2. ASSUME caller allows destruction.
- ; Dump's data is at "body" -- a sequence of pixels in src2seg.
- ; ALL CALLER'S MUST PUSH BX & CX, AND ONLY those registers, so that
- ; "Dincompressible" will pop correct #words.
- PutDump:
- jcxz noDump ; No data to dump.
- IF 0
- call DumpPutDump
- ENDIF
- push ax ; Hold AX.
- ; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible.
-
- mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI.
- les di,MR_DST_FAR[bp] ; SET ES:DI:dst.
-
- mov dx,MR_DST_LIMIT[bp] ; Check for incompressible.
- sub dx,cx
- jb Dincompressible ; (underflow -- "dstLimit < wordCnt")
- cmp di,dx
- ja Dincompressible ; "dstAddr > dstLimit-wordCnt"
- ; "Rinc..." because "incompressible" was out of range.
- ; It must be same condition test ("ja")!
-
- cmp cx,MAX_SHORT_DUMP ;
- ja lDump ; "cnt > MAX_SHORT_DUMP"
- mov ax,MR_WAS_X[bp]
- add ax,cx
- cmp ax,MR_SRC_WIDTH[bp]
- ja lDump ; "CROSSED_W(cnt)"
- mov al,OP_DUMP ; "*dst++ = OP_DUMP | cnt;"
- add al,cl
- stosb
- jmp short dBody
- lDump: ; longDump op.
- mov al,LONG_OP ; "*dst++ = LONG_OP;"
- stosb
- mov ax,cx ; "*((UWORD far *)dst++ = "
- or ah,LONG_DUMP ; " (LONG_DUMP<<8) | cnt);"
- stosw
- dBody:
- xchg bx,si ; Hold SI:src2. SET BX:body.
- rep movsb ; DS:SI:body, ES:DI:dst, CX:cnt.
- ; Note: dst is ++ past the new data.
- xchg bx,si ; Restore SI:src2.
-
- mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr.
- les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1.
- pop ax ; Restore AX.
- noDump: retn ; NEAR.
-
- IF 0 ; debugging
- DumpPutRun:
- push ds
- push es
- push ax
- push bx
- push cx
- push dx
- mov al,ah
- sub ah,ah
- push ax
- push cx
- mov ax,ss
- mov ds,ax
- mov es,ax
- lea ax,DGROUP:runMsg
- push ax
- test _doDump,0ffh
- jz noR
- add _TotBytes,cx
- call _printf
- noR:
- add sp,6
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
- pop ds
- retn
-
- DumpPutDump:
- push ds
- push es
- push ax
- push bx
- push cx
- push dx
- push cx
- mov ax,ss
- mov ds,ax
- mov es,ax
- lea ax,DGROUP:dumpMsg
- push ax
- test _doDump,0ffh
- jz noD
- add _TotBytes,cx
- call _printf
- noD:
- add sp,4
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
- pop ds
- retn
-
- DumpPutSkip:
- push ds
- push es
- push ax
- push bx
- push cx
- push dx
- push cx
- mov ax,ss
- mov ds,ax
- mov es,ax
- lea ax,DGROUP:skipMsg
- push ax
- test _doDump,0ffh
- jz noS
- add _TotBytes,cx
- call _printf
- noS:
- add sp,4
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
- pop ds
- retn
-
- DumpClipX:
- push ds
- push es
- push ax
- push bx
- push cx
- push dx
- mov ax,ss
- mov ds,ax
- mov es,ax
- push di ; dest
- lea ax,DGROUP:clipMsg
- push ax
- test _doDump,0ffh
- jz noC
- call _printf
- noC:
- add sp,4
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
- pop ds
- retn
-
- DumpFinal:
- push ds
- push es
- push ax
- push bx
- push cx
- push dx
- mov ax,ss
- mov ds,ax
- mov es,ax
- mov ax,MR_FINAL_ROW_WIDTH[bp]
- push ax
- push di ; dest
- lea ax,DGROUP:finalMsg
- push ax
- test _doDump,0ffh
- jz noF
- call _printf
- noF:
- add sp,6
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
- pop ds
- retn
- ENDIF ; Debugging
- ENDPROC _MakeRunSkipDump
- ENDIF ; RunSkipDump format.
-
-
- IF 0 ; simple dump format.
- ;-----------------------------------------------------------------
- ; void AsmPlayDelta(UWORD picSeg, deltaSeg, deltaAddr, deltaBytes);
- ; Finishes playing the current delta-encoding format.
- ;-----------------------------------------------------------------
-
- public _AsmPlayDelta
- STARTPROC _AsmPlayDelta
-
- APD_PIC_SEG = ARGB
- APD_DELTA_SEG = ARGB+2
- APD_DELTA_ADDR = ARGB+4
- APD_DELTA_BYTES = ARGB+6
-
- push bp
- mov bp,sp
- push si
- push di
- push es
-
- mov si,APD_DELTA_ADDR[bp]
- mov dx,APD_DELTA_BYTES[bp]
- mov es,APD_PIC_SEG[bp]
-
- push ds ; Save DS:DGROUP.
- mov ds,APD_DELTA_SEG[bp] ; SET DS:deltaSeg. NOT DGROUP.
-
- jmp short more ; In case no data.
-
- runLoop:
- lodsw
- mov di,ax ; SET DI:picAddr
- lodsw
- mov cx,ax ; SET CX:runCount
- rep movsb ; far_movmem
-
- more: cmp si,dx ; while (deltaAddr < deltaBytes)
- jb runLoop
-
- pop ds ; Restore DS:DGROUP.
-
- pop es
- pop di
- pop si
- pop bp
- ret
-
- ENDPROC _AsmPlayDelta
-
-
- ;-----------------------------------------------------------------
- ; UWORD MakeDeltaSequence(UWORD picSeg, prevSeg, minAddr, maxAddr,
- ; deltaSeg, deltaAddr, limitAddr);
- ;
- ; Given a sequence of bytes in the same position in two images,
- ; create a delta-description to convert one image to the other.
- ;
- ; Puts the delta at (deltaSeg,deltaAddr).
- ; RETURNS "deltaBytes" -- # bytes to describe the delta, INCLUDING
- ; the initial "deltaAddr" value.
- ; "limitAddr" is offset into deltaSeg that may not be overwritten.
- ; RETURNS "-1" if doesn't fit.
- ;-----------------------------------------------------------------
-
- DOESNT_FIT = -1
-
- O_PIC_SEG = ARGB
- O_PREV_SEG = ARGB+2
- O_MIN_ADDR = ARGB+4
- O_MAX_ADDR = ARGB+6
- O_DELTA_SEG = ARGB+8
- O_DELTA_ADDR = ARGB+10
- O_LIMIT_ADDR = ARGB+12
-
- public _MakeDeltaSequence
- STARTPROC _MakeDeltaSequence
-
- push bp
- mov bp,sp
- push si
- push di
- push es
-
- mov si,O_MIN_ADDR[bp] ; SET SI:picAddr = minAddr.
- mov es,O_PREV_SEG[bp] ; SET ES:prevSeg
- mov dx,O_DELTA_SEG[bp] ; SET DX:deltaSeg
- mov di,O_DELTA_ADDR[bp] ; SET DI:deltaAddr
-
- push ds ; Save DS:DGROUP.
- mov ds,O_PIC_SEG[bp] ; SET DS:picSeg. NOT DGROUP.
-
- ; --- Not in a run. Look for differences.
- sub cx,cx ; SET CX:runCount.
- sub bx,bx ; SET BX:gapSize.
- jmp short growGap0
-
- gapStarted:
- growGap:
- inc bx ; BX:gapSize.
- inc si
- growGap0:
- cmp si,O_MAX_ADDR[bp]
- ja endWhileInGap
-
- ; --- Cmp pic byte to prev byte.
- mov al,es:[si] ; ES:prevSeg, SI:picAddr
- cmp al,[si] ; DS:picSeg, SI:picAddr
- je growGap
-
- ; --- A run is starting. Determine whether to append to previous run,
- ; or to output previous run.
- jcxz noPreviousRun ; So won't append initial gap to
- ; non-existent run.
-
- cmp bx,4 ; BX:gapSize
- jb smallGap
-
- endWhileInGap:
- jcxz done ; NO RUN EVER FOUND.
- ; --- Output previous run. ---
-
- mov ax,di ; Test whether would reach limitAddr.
- add ax,4 ; Run's addr & count.
- add ax,cx ; runCount.
- cmp ax,O_LIMIT_ADDR[bp]
- jb fits
- mov ax,DOESNT_FIT ; RETURN "DOESNT_FIT".
- jmp short fail
-
- fits:
- mov ax,es
- xchg ax,dx
- mov es,ax ; SET ES:deltaSeg, DX:prevSeg
-
- sub si,bx ; Move back past gap.
- sub si,cx ; SET SI:runAddr = picAddr - runCount
- mov ax,si ; *(WORD)(deltaSeg,deltaAddr)= runAddr,
- stosw ; deltaAddr += 2.
- mov ax,cx ; *(WORD)(deltaSeg,deltaAddr)= runCount,
- stosw ; deltaAddr += 2.
- rep movsb ; far_movmem picSeg|Addr => deltaSeg|Addr,
- ; runCount bytes. When done, SI:picAddr set past run,
- ; CX:runCount = 0.
- add si,bx ; Move forward over gap.
- mov ax,es
- xchg ax,dx
- mov es,ax ; SET ES:prevSeg, DX:deltaSeg
-
- cmp si,O_MAX_ADDR[bp] ; Extra check saved a few code bytes.
- ja done
-
- jmp short gapConsumed
-
- smallGap:
- add cx,bx ; Append gap to run.
- ; jmp short gapConsumed
-
- noPreviousRun:
- gapConsumed:
- sub bx,bx ; SET BX:gapSize
-
- ; --- When reach here, have already found one byte of run.
- ; ASSUME SI:picAddr still pointing at byte, CX:runCount already is zero.
-
- continueRun:
- inc si ; Move SI:picAddr past byte of run.
- inc cx ; CX:runCount.
- cmp si,O_MAX_ADDR[bp]
- ja endWhileInRun
-
- mov al,es:[si] ; ES:prevSeg, SI:picAddr
- cmp al,[si] ; DS:picSeg, SI:picAddr
- jne continueRun
- endWhileInRun:
- jmp short gapStarted ; SI points to first byte of gap.
- ; BX:gapSize = 0.
-
- done:
- mov ax,di ; RETURN deltaBytes = DI:deltaAddr.
- fail:
- pop ds ; Restore DS:DGROUP.
-
- pop es
- pop di
- pop si
- pop bp
- ret
-
- ENDPROC _MakeDeltaSequence
- ENDIF ; simple dump format.
-
- ENDPS anima
- end